package com.ky.tms.util;


import com.auth0.jwt.JWT;
import com.auth0.jwt.JWTVerifier;
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.exceptions.JWTDecodeException;
import com.auth0.jwt.interfaces.DecodedJWT;
import org.apache.commons.codec.digest.DigestUtils;
import org.apache.commons.lang3.StringUtils;

import javax.servlet.http.HttpServletRequest;
import java.io.UnsupportedEncodingException;
import java.util.Base64;
import java.util.Date;

public class JwtUtil {

    public final static String REQUEST_HEAD_TAG = "token";

    /**
     * 校验Token
     * @param token
     * @param secret
     * @return
     */

    public static boolean verify(String token, String secret){
        try {
            String jti = getJti(token);
            if(StringUtils.isEmpty(jti)){
                return false;
            }
            Algorithm algorithm = Algorithm.HMAC256(encrypt(secret, jti));
            String username = getSubject(token);
            JWTVerifier verifier = JWT.require(algorithm).withSubject(username).build();
            verifier.verify(token);
            return true;
        } catch (Exception exception) {
            exception.printStackTrace();
            return  false;
        }
    }

    /**
     * 获得token中的信息
     * @return token中包含的Subject
     */
    public static String getSubject(String token) {
        try {
            DecodedJWT jwt = JWT.decode(token);

            return jwt.getSubject();
        } catch (JWTDecodeException e) {
            e.printStackTrace();
            return null;
        }
    }

    /**
     * 获得token中唯一标识
     * @param token
     * @return
     */
    public static String getJti(String token) {
        try {
            DecodedJWT jwt = JWT.decode(token);
            return jwt.getId();
        } catch (JWTDecodeException e) {
            e.printStackTrace();
            return null;
        }
    }

    /**
     * 获得token拥有角色
     * @param request
     * @return
     */
    public static String getRoles(HttpServletRequest request){
        try {
            String token = request.getHeader(REQUEST_HEAD_TAG);
            DecodedJWT jwt = JWT.decode(token);
            return jwt.getClaim("roles").asString();
        } catch (JWTDecodeException e) {
            e.printStackTrace();
            return null;
        }
    }

    /**
     * 获取取token过期时间
     * @param token
     * @return
     */
    public static Long getExp(String token){
        try{
            DecodedJWT jwt = JWT.decode(token);
            Date iat = jwt.getIssuedAt();
            Date exp = jwt.getExpiresAt();
            return exp.getTime() - iat.getTime();
        }catch (JWTDecodeException e){
            e.printStackTrace();
            return null;
        }
    }

    /**
     * 获取取token自动登陆
     * @param token
     * @return
     */
    public static String getStorageStatus(String token){
        try{
            DecodedJWT jwt = JWT.decode(token);
            return jwt.getClaim("sessionStatus").asString();
        }catch (JWTDecodeException e){
            e.printStackTrace();
            return null;
        }
    }

    public static String refresh(String token, String secret) {
        DecodedJWT jwt = JWT.decode(token);
        String subject = jwt.getSubject();
        String id = jwt.getId();
        Date issuedAt = jwt.getIssuedAt();
        Date expiresAt = jwt.getExpiresAt();
        Date notBefore = jwt.getNotBefore();
        String roles = jwt.getClaim("roles").asString();
        String storageStatus = jwt.getClaim("storageStatus").asString();
        Date nowIat = new Date();
        Date exp = new Date();
        exp.setTime(nowIat.getTime()+expiresAt.getTime()- issuedAt.getTime());
        return sign(secret, subject, nowIat, exp, notBefore, id, storageStatus, roles);
    }


    /**
     * 生成签名,加时间过期
     * @param  secret 私钥
     * @param  subject 受众
     * @param  iat 签发时间
     * @param  exp 过期时间
     * @param  nbf 生效时间
     * @param  nbf 类型
     * @param  jti 唯一标识
     * @param  storageStatus 自动登陆
     * @param  roles 拥有角色
     * @return token
     */
    public static String sign(final String secret,
                              final String subject,
                              final Date iat,
                              final Date exp,
                              final Date nbf,
                              final String jti,
                              final String storageStatus,
                              final String roles) {
        Algorithm algorithm;
        try {
            algorithm = Algorithm.HMAC256(encrypt(secret, jti));
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
            return null;
        }

        return JWT.create().withSubject(subject)
                .withIssuedAt(iat)
                .withJWTId(jti)
                .withExpiresAt(exp)
                .withNotBefore(nbf)
                .withClaim("roles", roles)
                .withClaim("storageStatus", storageStatus)
                .sign(algorithm);
    }

    /**
     * 根据请求头获取用户名
     * @param request
     * @return
     */
    public static String getUserName(HttpServletRequest request){
        String header = request.getHeader(REQUEST_HEAD_TAG);
        if(StringUtils.isBlank(header) || "null".equals(header)){
            return null;
        }
        return getSubject(header);
    }

    private static String encrypt (String secret, String slat){
        return DigestUtils.md5Hex(DigestUtils.md5Hex(Base64.getEncoder().encodeToString(secret.getBytes())+Base64.getEncoder().encodeToString(slat.getBytes())));
    }

}
